home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’96
/
FinderFlocks
/
FinderFun
/
AppleEventUtilities.cp
next >
Wrap
Text File
|
1996-06-22
|
75KB
|
2,209 lines
/*
File: AppleEventUtilities.cp
Contains: C++ Wrappers for Apple Event manager
*/
#ifndef __APPLEEVENTUTILITIES__
#include "AppleEventUtilities.h"
#endif
#ifndef __ASREGISTRY__
#include <ASRegistry.h>
#endif
#ifndef Exceptions_h
#include "Exceptions.h"
#endif
#ifndef __OSUTILS__
#include <OSUtils.h>
#endif
#ifndef __SCRIPT__
#include <Script.h>
#endif
#ifndef __APPLEEVENTS__
#include <AppleEvents.h>
#endif
#ifndef __AEOBJECTS__
#include <AEObjects.h>
#endif
#ifndef __ALIASES__
#include <Aliases.h>
#endif
#ifndef __AEOBJECTPACKING__
#include <AEPackObject.h>
#endif
#ifndef __AEREGISTRY__
#include <AERegistry.h>
#endif
#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif
#pragma segment AEMStuff
MakeTokenDescriptorProcPtr gNullContainerCreationProc = nil;
ProcessDescriptorProcPtr gPreResolveProc = nil;
MergeTokensProcPtr gMergeTokensProc = nil;
short TDescriptor::fCallbackFlags = kAEIDoMinimum;
//----------------------------------------------------------------------------------------
// InstallNullContainerCreationProc:
//
// The null container creation proc is used by TDescriptor::Resolve whenever it receives
// a null descriptor to resolve. This function is used to create a token for the null
// container.
//----------------------------------------------------------------------------------------
void InstallNullContainerCreationProc(MakeTokenDescriptorProcPtr creationProc)
{
gNullContainerCreationProc = creationProc;
} // InstallNullContainerCreationProc
//----------------------------------------------------------------------------------------
// InstallPreResolveProc:
//
// The PreResolveProc is called by TDescriptor::Resolve before it actually calls
// AEResolve. This allows special procs to handle things not understood by AEResolve
// (alias records, for example).
//----------------------------------------------------------------------------------------
void InstallPreResolveProc(ProcessDescriptorProcPtr preResolveProc)
{
gPreResolveProc = preResolveProc;
} // InstallPreResolveProc
//----------------------------------------------------------------------------------------
// InstallMergeTokensProc:
//
// The MergeTokensProc is called by TTokenDescriptor::AdoptToken whenever it needs to add
// a token object to any token descriptor that already contains a token. The merge token
// proc is provided with two TAbstractScriptableObject*'s; it must return a
// TAbstractScriptableObject* that has adopted the two tokens passed to it.
//----------------------------------------------------------------------------------------
void InstallMergeTokensProc(MergeTokensProcPtr mergeTokensProc)
{
gMergeTokensProc = mergeTokensProc;
} // InstallMergeTokensProc
//----------------------------------------------------------------------------------------
// CreateNullContainerToken:
//----------------------------------------------------------------------------------------
TTokenDescriptor CreateNullContainerToken()
{
TTokenDescriptor nullContainer;
if(gNullContainerCreationProc != nil)
nullContainer = (*gNullContainerCreationProc)();
return nullContainer;
} // CreateNullContainerToken
//========================================================================================
// CLASS TDescriptor
//
// Class TDescriptor is a wrapper class for AEDesc objects.
//========================================================================================
//----------------------------------------------------------------------------------------
// TDescriptor::Dispose:
//
// Disposed of the descriptor and the data stored inside it.
//----------------------------------------------------------------------------------------
void TDescriptor::Dispose()
{
FailErr(AEDisposeDesc(*this));
} // TDescriptor::Dispose
//----------------------------------------------------------------------------------------
// TDescriptor::AttemptCoercion:
//
// Try to coerce the type of the descriptor to something else. This method will
// NOT fail if the coercion could not be done.
//----------------------------------------------------------------------------------------
OSErr TDescriptor::AttemptCoercion(DescType typeToCoerceTo)
{
OSErr err = noErr;
if(this->DescriptorType() != typeToCoerceTo)
{
TDescriptor tempDescriptor;
// If AECoerceDesc returns a non-zero result code, then
// tempDescriptor will be typeNull, and we don't need to
// worry about disposing of it.
err = AECoerceDesc(*this,typeToCoerceTo,(AEDesc*)&tempDescriptor);
if(err == noErr)
{
Try
{
Handle initialHandle = this->DataHandle();
Handle coercedHandle = tempDescriptor.DataHandle();
//
// If doing a coerce-in-place, try to do a SetHandleSize
// and then a BlockMove so that we end up using the same
// handle when we exit as we had when we entered. To do
// otherwise is to invite double-dispose/memory leak problems
// if some other peice of code still has a reference to
// the descriptor before it was coerced
//
if((initialHandle != nil) && (coercedHandle != nil))
{
Size coercedSize = GetHandleSize(coercedHandle);
SetHandleSize(initialHandle, coercedSize);
FailErr(MemError());
BlockMove(*coercedHandle, *initialHandle, coercedSize);
this->fDescriptorType = tempDescriptor.DescriptorType();
tempDescriptor.Dispose();
}
//
// There are a couple of rare cases (typeTrue and typeFalse)
// where the data handle is nil
//
else
{
//
// It's undesirable to go from a nil-handle to a non-nil
// handle, or visa-versa. Don't do it. Use 'Coerce'
// rather than 'CoerceInPlace' if this is necessary.
//
if((initialHandle != nil) || (coercedHandle != nil))
DebugStr("\pPotentially undesirable coerce-in-place");
//
// Try to dispose of the old descriptor (ignoring errors)
// and then plug in the values from the coerced descriptor
//
AEDisposeDesc(*this);
this->AdoptDesc(tempDescriptor);
}
}
Catch(err)
{
tempDescriptor.Dispose();
}
}
}
return err;
} // TDescriptor::AttemptCoercion
//----------------------------------------------------------------------------------------
// TDescriptor::CoerceInPlace:
//
// Require that this object be coerced to the specified data type. This method will
// fail if the coercion does not work.
//----------------------------------------------------------------------------------------
void TDescriptor::CoerceInPlace(DescType typeToCoerceTo)
{
FailErr(this->AttemptCoercion(typeToCoerceTo));
} // TDescriptor::CoerceInPlace
//----------------------------------------------------------------------------------------
// TDescriptor::Coerce:
//
// Require that this object be coerced to the specified data type. This method will
// fail if the coercion does not work.
//----------------------------------------------------------------------------------------
TDescriptor TDescriptor::Coerce(DescType typeToCoerceTo) const
{
TDescriptor coercedDescriptor;
FailErr(AECoerceDesc(*this,typeToCoerceTo,coercedDescriptor));
return coercedDescriptor;
} // TDescriptor::Coerce
//----------------------------------------------------------------------------------------
// TDescriptor::CoerceToStandardType:
//
// This method attempts to coerce its data into some form of standard type
// (e.g. typeChar or typeLongInteger). It is really annoying that someone can
// invent yet another data type that is coercable to text or as a long integer,
// but we wouldn't have any way to know that such a coercion should be attempted.
// typeMagnitude and typeEnumeration could throw us for a loop too.
//
// ••• In short, I really hate this routine, but I'm not sure what else to do about it.
//----------------------------------------------------------------------------------------
void TDescriptor::CoerceToStandardType()
{
switch(this->DescriptorType())
{
case typeAEText:
case typeIntlText:
case typeStyledText:
{
this->CoerceInPlace(typeChar);
break;
}
case typeShortInteger:
{
this->CoerceInPlace(typeLongInteger);
break;
}
}
} // TDescriptor::CoerceToStandardType
//----------------------------------------------------------------------------------------
// TDescriptor::Clone:
//
// Return an exact copy of this descriptor
//----------------------------------------------------------------------------------------
TDescriptor TDescriptor::Clone() const
{
TDescriptor clonedDescriptor;
FailErr(AEDuplicateDesc(*this, (AEDesc*)&clonedDescriptor));
return clonedDescriptor;
} // TDescriptor::Clone
//----------------------------------------------------------------------------------------
// TDescriptor::CopyDesc:
//----------------------------------------------------------------------------------------
void TDescriptor::CopyDesc(const TDescriptor& desc)
{
FailErr(AEDuplicateDesc((AEDesc*)&desc, *this));
} // TDescriptor::CopyDesc
//----------------------------------------------------------------------------------------
// TDescriptor::AdoptDesc:
//----------------------------------------------------------------------------------------
void TDescriptor::AdoptDesc(TDescriptor& desc)
{
//
// It would be very tempting to set 'desc' to the null descriptor now
// that we have adopted it here. That would be a bad idea, though, because
// we might intend this descriptor to actually be just a reference to
// the adopted desc, and not actually the new 'owner' of the data.
//
this->AdoptHandle(desc.DescriptorType(), desc.DataHandle());
} // TDescriptor::AdoptDesc
//----------------------------------------------------------------------------------------
// TDescriptor::CreateList:
//
// Create an empty descriptor list or AERecord with factored data.
//
// n.b. It is better to call MakeList, MakeEmptyList or MakeAERecord rather than
// using TDescriptor::CreateList directly.
//----------------------------------------------------------------------------------------
void TDescriptor::CreateList(Boolean isRecord, Ptr factoringPtr, Size factoredSize)
{
FailErr(AECreateList(factoringPtr, factoredSize, isRecord, *this));
} // TDescriptor::CreateList
//----------------------------------------------------------------------------------------
// TDescriptor::MakeNull:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeNull()
{
this->AdoptHandle(typeNull, nil);
} // TDescriptor::MakeNull
//----------------------------------------------------------------------------------------
// TDescriptor::AdoptHandle:
//
// Assign some data and a type directly to the descriptor
//----------------------------------------------------------------------------------------
void TDescriptor::AdoptHandle(DescType dataType, Handle dataHandle)
{
fDescriptorType = dataType;
fDataHandle = dataHandle;
} // TDescriptor::AdoptHandle
//----------------------------------------------------------------------------------------
// TDescriptor::CopyData:
//----------------------------------------------------------------------------------------
void TDescriptor::CopyData(const DescType typeCode, const Ptr data, const Size length)
{
FailErr(AECreateDesc(typeCode, data, length, *this));
} // TDescriptor::CopyData
//----------------------------------------------------------------------------------------
// TDescriptor::MakeBoolean:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeBoolean(const Boolean data)
{
this->CopyData(typeBoolean, (Ptr)&data, sizeof(Boolean));
} // TDescriptor::MakeBoolean
//----------------------------------------------------------------------------------------
// TDescriptor::MakeLong:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeLong(const long data)
{
this->CopyData(typeLongInteger, (Ptr)&data, sizeof(long));
} // TDescriptor::MakeLong
//----------------------------------------------------------------------------------------
// TDescriptor::MakeUnsignedLong:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeUnsignedLong(const unsigned long data)
{
this->CopyData(typeMagnitude, (Ptr)&data, sizeof(unsigned long));
} // TDescriptor::MakeUnsignedLong
//----------------------------------------------------------------------------------------
// TDescriptor::MakeEnumeration:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeEnumeration(const DescType enumeration)
{
this->CopyData(typeEnumeration, (Ptr)&enumeration, sizeof(enumeration));
} // TDescriptor::MakeEnumeration
//----------------------------------------------------------------------------------------
// TDescriptor::MakeDescType:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeDescType(const DescType data)
{
this->CopyData(typeType, (Ptr)&data, sizeof(DescType));
} // TDescriptor::MakeDescType
//----------------------------------------------------------------------------------------
// TDescriptor::MakeKeyword:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeKeyword(const AEKeyword theKeyword)
{
this->CopyData(typeKeyword, (Ptr)&theKeyword, sizeof(AEKeyword));
} // TDescriptor::MakeKeyword
//----------------------------------------------------------------------------------------
// TDescriptor::MakeOrdinal:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeOrdinal(const DescType data)
{
this->CopyData(typeAbsoluteOrdinal, (Ptr)&data, sizeof(DescType));
} // TDescriptor::MakeOrdinal
//----------------------------------------------------------------------------------------
// TDescriptor::MakeTypeOrInteger:
//
// This is useful for debugging; it makes a 'type' if the data
// appears to consist of printable characters (e.g. 'ABCD'), but
// otherwise it makes an integer (e.g. -12).
//----------------------------------------------------------------------------------------
void TDescriptor::MakeTypeOrInteger(const DescType data)
{
if(((data >= 'A000') && (data <= 'Zzzz')) || ((data >= 'a000') && (data <= 'zzzz')))
this->MakeDescType(data);
else
this->MakeLong(data);
} // TDescriptor::MakeTypeOrInteger
//----------------------------------------------------------------------------------------
// TDescriptor::MakePoint:
//----------------------------------------------------------------------------------------
void TDescriptor::MakePoint(const Point& thePoint)
{
this->CopyData(typeQDPoint, (Ptr)&thePoint, sizeof(Point));
} // TDescriptor::MakePoint
//----------------------------------------------------------------------------------------
// TDescriptor::MakePoint:
//----------------------------------------------------------------------------------------
void TDescriptor::MakePoint(const short h, const short v)
{
Point thePoint;
thePoint.v = v;
thePoint.h = h;
this->MakePoint(thePoint);
} // TDescriptor::MakePoint
//----------------------------------------------------------------------------------------
// TDescriptor::MakeRect:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeRect(const Rect& theRect)
{
this->CopyData(typeQDRectangle, (Ptr)&theRect, sizeof(Rect));
} // TDescriptor::MakeRect
//----------------------------------------------------------------------------------------
// TDescriptor::MakeString:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeString(Str255 data)
{
Size length = data[0];
this->CopyData(typeChar, (Ptr)&data[1], length);
} // TDescriptor::MakeString
//----------------------------------------------------------------------------------------
// TDescriptor::MakeDateTimeRec:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeDateTimeRec(const DateTimeRec dateTime)
{
this->CopyData(typeDateTimeRec, (Ptr)&dateTime, sizeof(DateTimeRec));
} // TDescriptor::MakeDateTimeRec
//----------------------------------------------------------------------------------------
// TDescriptor::MakeDateTimeRec:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeDateTimeRec(const long secsSince1904)
{
DateTimeRec dateTime;
//
// Let the OSUtilities do the hard work of converting seconds
// since 1904 into a DateTimeRec
//
Secs2Date(secsSince1904,&dateTime);
this->MakeDateTimeRec(dateTime);
} // TDescriptor::MakeDateTimeRec
//----------------------------------------------------------------------------------------
// TDescriptor::MakeLongDateTimeRec:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeLongDateTimeRec(const LongDateRec dateTime)
{
this->CopyData(typeLongDateTimeRec, (Ptr)&dateTime, sizeof(LongDateRec));
} // TDescriptor::MakeLongDateTimeRec
//----------------------------------------------------------------------------------------
// TDescriptor::MakeLongDateTimeRec:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeLongDateTimeRec(const DateTimeRec dateTime)
{
LongDateRec longDateTime;
longDateTime.od.eraAlt = 0;
longDateTime.od.oldDate = dateTime;
this->MakeLongDateTimeRec(longDateTime);
} // TDescriptor::MakeLongDateTimeRec
//----------------------------------------------------------------------------------------
// TDescriptor::MakeLongDateTimeRec:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeLongDateTimeRec(LongDateTime lsecs)
{
LongDateRec longDateTime;
LongSecs2Date(&lsecs, &longDateTime);
this->MakeLongDateTimeRec(longDateTime);
} // TDescriptor::MakeLongDateTimeRec
//----------------------------------------------------------------------------------------
// TDescriptor::MakeLongDateTime:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeLongDateTime(const LongDateTime lsecs)
{
this->CopyData(typeLongDateTime, (Ptr)&lsecs, sizeof(LongDateTime));
} // TDescriptor::MakeLongDateTime
//----------------------------------------------------------------------------------------
// TDescriptor::MakeFSS:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeFSS(const FSSpec& spec)
{
this->CopyData(typeFSS, (Ptr)&spec, sizeof(FSSpec));
} // TDescriptor::MakeFSS
//----------------------------------------------------------------------------------------
// TDescriptor::AdoptAlias:
//
// Takes the provided alias handle and keeps it forever.
//----------------------------------------------------------------------------------------
void TDescriptor::AdoptAlias(Handle alias)
{
this->AdoptHandle(typeAlias, alias);
} // TDescriptor::AdoptAlias
//----------------------------------------------------------------------------------------
// TDescriptor::MakeAlias:
//
// You would think that someone would have spent five minutes to make a coercion
// handler that goes from FSSpecs to Alias records, but nooooooo...
//----------------------------------------------------------------------------------------
void TDescriptor::MakeAlias(FSSpec& spec)
{
AliasHandle alias;
FailErr(NewAliasMinimal(&spec, &alias));
this->AdoptAlias((Handle)alias);
} // TDescriptor::MakeAlias
//----------------------------------------------------------------------------------------
// TDescriptor::MakeProcessSerialNumber:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeProcessSerialNumber(ProcessSerialNumber psn)
{
this->CopyData(typeProcessSerialNumber, (Ptr)&psn, sizeof(ProcessSerialNumber));
} // TDescriptor::MakeProcessSerialNumber
//----------------------------------------------------------------------------------------
// TDescriptor::MakeObjectSpecifier:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeObjectSpecifier(DescType desiredClass, TDescriptor container, DescType keyForm, TDescriptor keyData, Boolean disposeInputs)
{
FailErr(CreateObjSpecifier(desiredClass,container,keyForm,keyData,disposeInputs,*this));
} // TDescriptor::MakeObjectSpecifier
//----------------------------------------------------------------------------------------
// TDescriptor::MakeCompDescriptor:
//----------------------------------------------------------------------------------------
void TDescriptor::MakeCompDescriptor(DescType comparisonOperator, DescType propertyIdentifier, TDescriptor compareWith, Boolean disposeInputs)
{
TDescriptor operand1;
TDescriptor propertyIDDesc;
TDescriptor objectBeingExamined;
//
// 'objectBeingExamined' is a special object specifier that only
// has meaning in the context of a comparison descriptor
//
objectBeingExamined.AdoptHandle(typeObjectBeingExamined,nil);
//
// Operand1 is "fPropertyIdentifier of (object being examined)"
//
propertyIDDesc.MakeDescType(propertyIdentifier);
operand1.MakeObjectSpecifier(cProperty, objectBeingExamined, formPropertyID, propertyIDDesc, true);
//
// Make a compDescriptor of operand1 compared with (fComparisonOperator) fCompareWith
//
CreateCompDescriptor(comparisonOperator, operand1, compareWith, disposeInputs, *this);
} // TDescriptor::MakeCompDescriptor
//----------------------------------------------------------------------------------------
// TDescriptor::GetBlock:
//----------------------------------------------------------------------------------------
void TDescriptor::GetBlock(Ptr data, Size length, DescType desiredType) const
{
if(this->DataHandleIsNil())
FailErr(errAECantSupplyType);
if(this->DescriptorType() != desiredType)
{
TDescriptor coerceData;
coerceData = this->Coerce(desiredType);
coerceData.GetBlock(data,length,desiredType);
coerceData.Dispose();
}
else
{
//
// It would be just wrong to have a situation where a
// descriptor is of the requested type, but not of the
// requested length. This method is only usable for
// fixed-size blocks
//
if(GetHandleSize(fDataHandle) != length)
{
FailErr(errAECorruptData);
}
BlockMove(*fDataHandle, data, length);
}
} // TDescriptor::GetBlock
//----------------------------------------------------------------------------------------
// TDescriptor::GetLong:
//----------------------------------------------------------------------------------------
long TDescriptor::GetLong() const
{
long result = 0;
this->GetBlock((Ptr)&result, sizeof(long), typeLongInteger);
return result;
} // TDescriptor::GetLong
//----------------------------------------------------------------------------------------
// TDescriptor::GetBoolean:
//----------------------------------------------------------------------------------------
Boolean TDescriptor::GetBoolean() const
{
Boolean result = 0;
this->GetBlock((Ptr)&result, sizeof(Boolean), typeBoolean);
return result;
} // TDescriptor::GetBoolean
//----------------------------------------------------------------------------------------
// TDescriptor::GetDescType:
//----------------------------------------------------------------------------------------
DescType TDescriptor::GetDescType() const
{
DescType result = 0;
this->GetBlock((Ptr)&result, sizeof(DescType), typeType);
return result;
} // TDescriptor::GetDescType
//----------------------------------------------------------------------------------------
// TDescriptor::GetKeyword:
//----------------------------------------------------------------------------------------
AEKeyword TDescriptor::GetKeyword() const
{
AEKeyword result = 0;
this->GetBlock((Ptr)&result, sizeof(AEKeyword), typeKeyword);
return result;
} // TDescriptor::GetKeyword
//----------------------------------------------------------------------------------------
// TDescriptor::GetEnumeration:
//----------------------------------------------------------------------------------------
DescType TDescriptor::GetEnumeration() const
{
DescType result = 0;
this->GetBlock((Ptr)&result, sizeof(DescType), typeEnumeration);
return result;
} // TDescriptor::GetEnumeration
//----------------------------------------------------------------------------------------
// TDescriptor::GetOrdinal:
//----------------------------------------------------------------------------------------
DescType TDescriptor::GetOrdinal() const
{
DescType result = 0;
this->GetBlock((Ptr)&result, sizeof(DescType), typeAbsoluteOrdinal);
return result;
} // TDescriptor::GetOrdinal
//----------------------------------------------------------------------------------------
// TDescriptor::GetPoint:
//----------------------------------------------------------------------------------------
Point TDescriptor::GetPoint() const
{
Point result;
this->GetBlock((Ptr)&result, sizeof(Point), typeQDPoint);
return result;
} // TDescriptor::GetPoint
//----------------------------------------------------------------------------------------
// TDescriptor::GetRect:
//----------------------------------------------------------------------------------------
Rect TDescriptor::GetRect() const
{
Rect result;
this->GetBlock((Ptr)&result, sizeof(Rect), typeQDRectangle);
return result;
} // TDescriptor::GetRect
//----------------------------------------------------------------------------------------
// TDescriptor::GetString:
//----------------------------------------------------------------------------------------
void TDescriptor::GetString(Str255 result) const
{
result[0] = 0;
if(this->DataHandleIsNil())
FailErr(errAECantSupplyType);
if(this->DescriptorType() == typeChar)
{
Size length = GetHandleSize(fDataHandle);
if(length > 255)
length = 255;
BlockMove(*fDataHandle, (Ptr)&result[1], length);
result[0] = (unsigned char) length;
}
else
{
TDescriptor makeDataString;
makeDataString = this->Coerce(typeChar);
ASSERT(makeDataString.DescriptorType() == typeChar);
makeDataString.GetString(result);
makeDataString.Dispose();
}
} // TDescriptor::GetString
//----------------------------------------------------------------------------------------
// TDescriptor::GetDateTimeRec:
//----------------------------------------------------------------------------------------
DateTimeRec TDescriptor::GetDateTimeRec() const
{
DateTimeRec dateTime;
//
// We'll do our own coercion from typeLongInteger, if necessary.
// We should really have a coercion handler for this
//
if(this->DescriptorType() == typeLongInteger)
{
long secsSince1904 = this->GetLong();
Secs2Date(secsSince1904,&dateTime);
}
else
{
//
// Get the time date rec
//
this->GetBlock( (Ptr)&dateTime, sizeof(DateTimeRec), typeDateTimeRec);
}
return dateTime;
} // TDescriptor::GetDateTimeRec
//----------------------------------------------------------------------------------------
// TDescriptor::GetFSS:
//----------------------------------------------------------------------------------------
void TDescriptor::GetFSS(FSSpec& spec) const
{
this->GetBlock((Ptr)&spec, sizeof(FSSpec), typeFSS);
} // TDescriptor::GetFSS
//----------------------------------------------------------------------------------------
// InterpretCompareResult:
//
// Given two keys and a comparison opperator, this function determines if
// the comparison between key2 and key1 is true or false. key1 and key2 should
// be either two long integers representing the various values of the two descriptors
// being compared, or key1 may be set to 0 and key2 set to -1 (key2 < key1), 0
// (key1 == key2) or 1 (key2 > key1).
//
// This function is used by GeneralCompare, which is used by TDescriptor::Compare
//----------------------------------------------------------------------------------------
Boolean InterpretCompareResult(DescType comparisonOperator, long key1, long key2 )
{
switch(comparisonOperator)
{
case kAEEquals:
{
return key1 == key2;
}
case kASNotEqual:
{
return key1 != key2;
}
case kAEGreaterThan:
{
return key1 > key2;
}
case kAEGreaterThanEquals:
{
return key1 >= key2;
}
case kAELessThan:
{
return key1 < key2;
}
case kAELessThanEquals:
{
return key1 <= key2;
}
//
// ••• Perhaps we should fail if we don't recognize the comparisonOperator
//
default:
{
return false;
}
}
} // InterpretCompareResult
//----------------------------------------------------------------------------------------
// GeneralCompare:
//
// This is a general comparison routine that works on streams of bytes. It is assumed
// that the data being compared follows the same ordering rules as strings. The
// 'caseSensitive' flag should always be true for non-string objects, of course.
//----------------------------------------------------------------------------------------
Boolean GeneralCompare(DescType comparisonOperator, Ptr data, Size length, Ptr compareWith, Size comparisonLength, Boolean caseSensitive)
{
Boolean comparisonResult = false;
long i = 0;
switch(comparisonOperator)
{
case kAEEquals:
case kASNotEqual:
case kAEGreaterThan:
case kAEGreaterThanEquals:
case kAELessThan:
case kASLessThanOrEqual:
{
short intermediateResult = 0;
Size max = (length < comparisonLength ? length : comparisonLength);
//
// We have a little bit of code duplication here
// to make the code run a little faster
//
if(caseSensitive)
{
for(i=0; i < max; ++i)
{
if(*((unsigned char*)compareWith) > *((unsigned char*)data))
{
intermediateResult = 1;
break;
}
else if(*((unsigned char*)compareWith) < *((unsigned char*)data))
{
intermediateResult = -1;
break;
}
++compareWith;
++data;
}
}
else
{
for(i=0; i < max; ++i)
{
unsigned char compareWithChar = *((unsigned char*)compareWith);
unsigned char dataChar = *((unsigned char*)data);
if((compareWithChar >= 'a') && (compareWithChar <= 'z'))
compareWithChar = compareWithChar - 'a' + 'A';
if((dataChar >= 'a') && (dataChar <= 'z'))
dataChar = dataChar - 'a' + 'A';
if(compareWithChar > dataChar)
{
intermediateResult = 1;
break;
}
else if(compareWithChar < dataChar)
{
intermediateResult = -1;
break;
}
++compareWith;
++data;
}
}
if(intermediateResult == 0)
intermediateResult = (comparisonLength > length) - (comparisonLength < length);
comparisonResult = InterpretCompareResult(comparisonOperator,0,intermediateResult);
break;
}
case kAEBeginsWith:
{
comparisonResult = GeneralCompare(kAEEquals, data, comparisonLength, compareWith, comparisonLength,caseSensitive);
break;
}
case kAEEndsWith:
{
i = (length - comparisonLength);
if(i >= 0)
comparisonResult = GeneralCompare(kAEEquals, data + i, comparisonLength, compareWith, comparisonLength,caseSensitive);
break;
}
case kAEContains:
{
for(i=0;i<=length - comparisonLength;++i)
{
if(GeneralCompare(kAEEquals, data + i, comparisonLength, compareWith, comparisonLength,caseSensitive))
{
comparisonResult = true;
break;
}
}
break;
}
default:
{
comparisonResult = false;
}
}
return comparisonResult;
} // GeneralCompare
//----------------------------------------------------------------------------------------
// StringContains:
//----------------------------------------------------------------------------------------
/*Boolean StringContains(Str255 thisString, Str255 withString)
{
unsigned char thisSize = (unsigned char)thisString[0];
unsigned char withSize = (unsigned char)withString[0];
if ((thisSize == 0) || (withSize > thisSize)) // quick check
return false;
Boolean b = false;
unsigned char* a = &thisString[0];
unsigned char* last = a + thisSize - withSize + 1;
do
{
b = IUMagIDString(Ptr(++a), Ptr(withString[1]), withSize, withSize);
}
while (b && (a < last));
return (b == false);
} // StringContains */
//----------------------------------------------------------------------------------------
// TDescriptor::Compare:
//----------------------------------------------------------------------------------------
Boolean TDescriptor::Compare(DescType comparisonOperator, Str255 withString) const
{
Str255 thisString;
Size thisSize;
Size withSize;
Boolean compareResult = false;
//
// Fetch a copy of 'thisString' (which we will freely destroy later)
//
this->GetString(thisString);
thisSize = (unsigned char)thisString[0];
withSize = (unsigned char)withString[0];
switch(comparisonOperator)
{
//
// Check to see if we can find the string anywhere inside
//
case kAEContains:
{
long i;
unsigned char* a = &thisString[0];
for(i=0;i<thisSize - withSize + 1;++i)
{
*a = (unsigned char)withSize;
compareResult = (IUEqualString(a, withString) == 0);
if(compareResult == true)
break;
++a;
}
}
break;
//
// Relational tests are easy: use IUCompString
//
case kAEGreaterThan:
case kAEGreaterThanEquals:
case kAELessThan:
case kASLessThanOrEqual:
{
compareResult = InterpretCompareResult(comparisonOperator, IUCompString(thisString, withString), 0);
}
break;
//
// For AEEndsWith, move the end of the string down to
// the beginning of the string, then fall through to
// the 'begins with' case
//
// International allert: this could clip a two-byte
// character in half, but doing so probably won't cause
// a problem, since we are looking for exact matches.
//
case kAEEndsWith:
{
if(withSize <= thisSize)
BlockMove((Ptr)&thisString[thisSize - withSize + 1],(Ptr)&thisString[1],withSize);
}
// !!! fall through
//
// For kAEBeginsWith, set the length of the 'thisString'
// to the length of the 'withString' and do an equality test
//
// International allert: this could clip a two-byte
// character in half, but doing so probably won't cause
// a problem, since we are looking for exact matches.
//
case kAEBeginsWith:
{
thisString[0] = (unsigned char)withSize;
}
// !!! fall through...
//
// kAEEquals and kASNotEqual must come immediately after
// begins with and ends with
//
case kAEEquals:
case kASNotEqual:
{
compareResult = (IUEqualString(thisString, withString) == 0);
if(comparisonOperator == kASNotEqual)
compareResult = !compareResult;
}
break;
//
// Shouldn't ever get here...
//
default:
{
compareResult = GeneralCompare(comparisonOperator,(Ptr)&thisString[1],thisSize,(Ptr)&withString[1],withSize,false);
}
break;
}
return compareResult;
} // TDescriptor::Compare
//----------------------------------------------------------------------------------------
// TDescriptor::Compare:
//
// Compare two descriptors. ComparisonOperator should be one of the following:
//
// kAEEquals, kASNotEqual, kAEGreaterThan, kAEGreaterThanEquals, kAELessThan,
// kASLessThanOrEqual, kAEBeginsWith, kAEEndsWith, or kAEContains
//----------------------------------------------------------------------------------------
Boolean TDescriptor::Compare(DescType comparisonOperator, TDescriptor& compareWith) const
{
Boolean compareResult = false;
//
// It might be nice to try to do a type coercion here, but for now
// we only compare descriptors of the same type
//
if(this->DescriptorType() != compareWith.DescriptorType())
FailErr(errAEEventNotHandled);
switch(this->DescriptorType())
{
case typeChar:
{
Str255 withString;
compareWith.GetString(withString);
compareResult = this->Compare(comparisonOperator, withString);
break;
}
break;
//
// We convert DateTimeRecs into integers for comparison so that
// someone can supply "the 300th day of January", and it will compare
// as being larger than "the 2nd day of February".
//
// Begins with, ends with and contains are meaningless for dates, though.
//
case typeLongInteger:
case typeDateTimeRec:
{
compareResult = InterpretCompareResult(comparisonOperator, this->GetLong(), compareWith.GetLong() );
}
break;
//
// If we don't know what type this is, we'll do our best
// to do a generic comparison. This can result in some
// very stupid comparisons, but that's life.
//
default:
{
Handle withHandle = compareWith.DataHandle();
short thisState;
short withState;
Size thisSize;
Size withSize;
thisState = HGetState(fDataHandle);
withState = HGetState(withHandle);
thisSize = GetHandleSize(fDataHandle);
withSize = GetHandleSize(withHandle);
compareResult = GeneralCompare(comparisonOperator,(Ptr)*fDataHandle,thisSize,(Ptr)*withHandle,withSize,true);
HSetState(fDataHandle,thisState);
HSetState(withHandle,withState);
}
break;
}
return compareResult;
} // TDescriptor::Compare
//========================================================================================
// CLASS TDescriptorLoop
//
// The class TDescriptorLoop is used by the macro FOREACHDESCRIPTOR. Note that the
// descriptor returned by "Next" is a copy that must be disposed of by the programmer.
//
// We could have TDescriptorLoop keep track of the descriptor it created, and have it
// dispose it when done. This would necessitate an 'orphan' method, though, in case
// someone else wanted to adopt the descriptor.
//========================================================================================
//----------------------------------------------------------------------------------------
// TDescriptorLoop::Next:
//
// If 'key' is not nil, it is filled in with the keyword from the i'th item of the
// list (if the list is a record)
//
// If 'dataHandle' is not nil, it is filled in with the data handle from the i'th
// item of the list. This is only done to be nice to the FOREACHTOKEN macro.
//----------------------------------------------------------------------------------------
Boolean TDescriptorLoop::Next(TDescriptor& d, AEKeyword* key, Handle* dataHandle)
{
Boolean moreToDo = false;
//
// Set up on the first time through the loop
//
if(fIndex == 0)
{
fCount = fDescriptorList->CountItems();
if(d.IsNullDescriptor() == false)
{
DebugStr("\pTDescriptorLoop::Next: 'd' was not null on first iteration!");
FailErr(errAEEventFailed);
}
}
//
// Advance to the next item in the list...
//
fIndex++;
//
// Dispose of the 'd' from last time through the loop
//
d.Dispose();
//
// Are there still items in the list?
//
if (fIndex <= fCount)
{
//
// At this point, we could check to see if 'fDescriptorList' actually
// points to something that is _not_ a list; if so, we coule return a
// _reference_ to the single object, and set a field that indicates that
// 'd' is a reference, and should not be disposed next time through the
// loop. The reason we do not do this is that 'd' will be disposed by
// the client code if there is a failure, and there is no good way for
// the client to know if d is a reference or not. We could remember
// what 'd' was and clean it up in our destructor, but failures can
// cause our TDescriptorLoop object to be orphaned without ever being
// destructed.
//
d = fDescriptorList->GetNthDescriptor(fIndex, typeWildCard, key);
moreToDo = true;
}
//
// No more items, clean up
//
else
{
if(key != nil)
*key = typeNull;
d.MakeNull();
}
//
// Fill in the 'dataHandle' parameter if it was passed in.
// (We only do this to make life easy for the FOREACHTOKEN macro)
//
if(dataHandle != nil)
*dataHandle = d.DataHandle();
return moreToDo;
} // TDescriptorLoop::Next
//----------------------------------------------------------------------------------------
// TDescriptor::MakeEmptyList:
//
// Make an empty descriptor list. It is usually not necessary to make an empty list,
// because all of the TDescriptor routines will interpret null descriptors as
// empty lists. Sometimes it is necessary to return an empty list as the result of
// an AppleEvent handler, though, and in this case a null descriptor is _not_ equivalent.
//
// By default, include no factored data and make an AEList.
//----------------------------------------------------------------------------------------
void TDescriptor::MakeEmptyList()
{
this->CreateList(kMakeAEList);
} // TDescriptor::MakeEmptyList
//----------------------------------------------------------------------------------------
// TDescriptor::MakeList:
//
// If this descriptor is null, an empty list is created. If this descriptor is not
// empty, then a list is created and this descriptor is placed inside it. If this
// descriptor is already a list, then no action is taken.
//
// ••• DANGER: Does a coerce-in-place!
//----------------------------------------------------------------------------------------
void TDescriptor::MakeList()
{
if(this->IsNullDescriptor())
{
this->CreateList();
}
else if(this->DescriptorType() != typeAEList)
{
this->CoerceInPlace(typeAEList);
}
} // TDescriptor::MakeList
//----------------------------------------------------------------------------------------
// TDescriptor::CountItems:
//
// Count the items in a descriptor list. If this descriptor is not of typeAEList, then it
// only has one item, and if the descriptor is null, then it has no items.
//----------------------------------------------------------------------------------------
long TDescriptor::CountItems() const
{
long items = 1;
if(this->IsNullDescriptor())
items = 0;
else if((this->DescriptorType() == typeAEList) || (this->DescriptorType() == typeAERecord))
FailErr(AECountItems(*this, &items));
return items;
} // TDescriptor::CountItems
//----------------------------------------------------------------------------------------
// TDescriptor::GetNthDescriptor:
//
// Get the indexed descriptor from an event. This method will fail if given an index
// less than one or greater than the count returned by TDescriptor::CountItems.
// The descriptor returned is _always_ a copy that must be disposed of with
// TDescriptor::Dispose.
//----------------------------------------------------------------------------------------
TDescriptor TDescriptor::GetNthDescriptor(long index, DescType desiredType, AEKeyword* key) const
{
TDescriptor descriptor;
AEKeyword ignoreKey;
if(key == nil)
key = &ignoreKey;
//
// We can "GetNthDescriptor" on an item that is not of typeAEList
// if the index is one; we do this by cloning ourself
// (n.b. AERecords are also lists)
//
if((DescriptorType() != typeAEList) && (DescriptorType() != typeAERecord))
{
if(index != 1)
FailErr(-1); // ••• index out of range
*key = typeWildCard;
descriptor = this->Clone();
}
else
{
FailErr(AEGetNthDesc(*this, index, desiredType, key, descriptor));
}
return descriptor;
} // TDescriptor::GetNthDescriptor
//----------------------------------------------------------------------------------------
// TDescriptor::AddDescriptor:
//
// Add data to a descriptor list at a specified index, replacing any item already stored
// at that position.
//----------------------------------------------------------------------------------------
void TDescriptor::AddDescriptor(long index, TDescriptor& data)
{
//
// If the list is completely empty, just put the data directly into
// this descriptor (don't make a list)
//
if(this->IsNullDescriptor())
{
this->CopyDesc(data);
}
else
{
// If we're not a list yet, we'd better make ourselves one now.
if(this->DescriptorType() != typeAEList)
this->MakeList();
FailErr(AEPutDesc(*this, index, data));
}
} // TDescriptor::AddDescriptor
//----------------------------------------------------------------------------------------
// TDescriptor::AddDescriptor:
//
// Add data to a descriptor list at the end of the list
//----------------------------------------------------------------------------------------
void TDescriptor::AddDescriptor(TDescriptor& data)
{
this->AddDescriptor(0,data);
} // TDescriptor::AddDescriptor
//----------------------------------------------------------------------------------------
// TDescriptor::AddData:
//----------------------------------------------------------------------------------------
void TDescriptor::AddData(long index, DescType descType, Ptr data, Size length)
{
//
// If the list is completely empty, we'd better make an empty list
// (the type coercion from null to typeAEList probably works,
// but I have not tested it yet; the following two lines may
// be superfluous)
//
if(this->IsNullDescriptor())
this->MakeEmptyList();
//
// If we're not a list yet, we'd better make ourselves one now.
//
if(this->DescriptorType() != typeAEList)
this->CoerceInPlace(typeAEList);
//
// Put the data into the list
//
FailErr(AEPutPtr(*this,index,descType,data,length));
} // TDescriptor::AddData
//----------------------------------------------------------------------------------------
// TDescriptor::AddData:
//----------------------------------------------------------------------------------------
void TDescriptor::AddData(DescType descType, Ptr data, Size length)
{
this->AddData(0,descType,data,length);
} // TDescriptor::AddData
//----------------------------------------------------------------------------------------
// TDescriptor::AddLong:
//----------------------------------------------------------------------------------------
void TDescriptor::AddLong(long number)
{
this->AddData(typeLongInteger,(Ptr)&number,sizeof(long));
} // TDescriptor::AddLong
//----------------------------------------------------------------------------------------
// TDescriptor::AddType:
//----------------------------------------------------------------------------------------
void TDescriptor::AddType(DescType descType)
{
this->AddData(typeType,(Ptr)&descType,sizeof(DescType));
} // TDescriptor::AddType
//----------------------------------------------------------------------------------------
// TDescriptor::AppendList:
//
// Append a list onto the end of this one. The list passed in may be a null descriptor
// or a single item as well as a list.
//----------------------------------------------------------------------------------------
void TDescriptor::AppendList(const TDescriptor& list)
{
TDescriptor descriptor;
OSErr err = noErr;
//
// If this descriptor is a null descriptor, then we just want
// to copy the incoming list.
//
// In the past we did not do this check, which resulted in
// the unfortunate side effect of converting a single-item
// list into a single (non-list) descriptor whenever said
// list was 'AppendList'ed into an empty list. While this
// may be more efficient, it really hosed us over in the case
// of GetData on the selection property, which is SUPPOSED
// to return a single-item list (as opposed to a single
// descriptor) if there is only one item in the list. (This
// is quite different from most other objects, which are
// supposed to return single descriptors instead of single-
// item lists whenever there is only one object in the result.)
//
if(this->IsNullDescriptor())
{
this->CopyDesc(list);
}
else if(list.IsNullDescriptor() == false)
{
Try
{
FOREACHDESCRIPTOR(&list, descriptor)
{
this->AddDescriptor(descriptor);
}
}
Catch(err)
{
descriptor.Dispose();
Throw(err);
}
}
} // TDescriptor::AppendList
//----------------------------------------------------------------------------------------
// TDescriptor::AdoptList:
//----------------------------------------------------------------------------------------
void TDescriptor::AdoptList(TDescriptor* list)
{
if(this->IsNullDescriptor())
{
this->AdoptDesc(*list);
}
else
{
this->AppendList(*list);
list->Dispose();
}
} // TDescriptor::AdoptList
//----------------------------------------------------------------------------------------
// TDescriptor::MakeAERecord:
//
// CreateList creates both AERecords and AELists.
//----------------------------------------------------------------------------------------
void TDescriptor::MakeAERecord()
{
this->CreateList(kMakeAERecord);
} // TDescriptor::MakeAERecord
//----------------------------------------------------------------------------------------
// TDescriptor::GetDescriptor:
//
// Get the ae descriptor from the event. If the desired type is not specified, it
// defaults to typeWildCard
//----------------------------------------------------------------------------------------
TDescriptor TDescriptor::GetDescriptor(AEKeyword key, DescType desiredType)
{
TDescriptor result;
//
// n.b. This object must be typeAERecord or typeAppleEvent, or this
// call will fail. Other record-like descriptors (e.g. object specifiers)
// cannot be passed to AEGetParamDesc.
//
FailErr(AEGetParamDesc(*this, key, desiredType, (AEDesc *) &result));
return result;
} // TDescriptor::GetDescriptor
//----------------------------------------------------------------------------------------
// TDescriptor::GetOptionalParameter:
//
// Like 'GetDescriptor, but returns a null descriptor if the specified parameter could not
// be extracted.
//----------------------------------------------------------------------------------------
TDescriptor TDescriptor::GetOptionalParameter(AEKeyword key, DescType desiredType)
{
TDescriptor result;
OSErr err = noErr;
//
// It's probably not necessary to call MakeNull if there is
// an error, but we might as well be safe (paranoid?).
//
err = AEGetParamDesc(*this, key, desiredType, (AEDesc *) &result);
if(err != noErr)
result.MakeNull();
return result;
} // TDescriptor::GetOptionalParameter
//----------------------------------------------------------------------------------------
// TDescriptor::GetParameterPtr:
//
// Get the ae descriptor from the record
//----------------------------------------------------------------------------------------
void TDescriptor::GetParameterPtr(AEKeyword key, DescType desiredType, DescType *typeCode, Ptr dataPtr, Size maximumSize, Size *actualSize)
{
//
// n.b. This object must be typeAERecord or typeAppleEvent, or this
// call will fail. Other record-like descriptors (e.g. object specifiers)
// cannot be passed to AEGetParamPtr.
//
FailErr(AEGetParamPtr(*this, key, desiredType, typeCode, dataPtr, maximumSize, actualSize));
} // TDescriptor::GetParameterPtr
//----------------------------------------------------------------------------------------
// TDescriptor::GetLongParameter:
//
// Get the first longword of data from a parameter coerced to the specified type
// (usually typeLongInteger)
//----------------------------------------------------------------------------------------
long TDescriptor::GetLongParameter(AEKeyword key, DescType desiredType)
{
long actualSize;
DescType typeCode;
long result = 0;
GetParameterPtr(key, desiredType, &typeCode, (Ptr) &result, sizeof(long), &actualSize);
return result;
} // TDescriptor::GetLongParameter
//----------------------------------------------------------------------------------------
// TDescriptor::GetShortParameter:
//
// Get the first shortword of data from a parameter coerced to the specified type
// (usually typeShortInteger)
//----------------------------------------------------------------------------------------
short TDescriptor::GetShortParameter(AEKeyword key, DescType desiredType)
{
long actualSize;
DescType typeCode;
short result = 0;
GetParameterPtr(key, desiredType, &typeCode, (Ptr) &result, sizeof(short), &actualSize);
return result;
} // TDescriptor::GetShortParameter
//----------------------------------------------------------------------------------------
// TDescriptor::GetDirectObject:
//
// Get the direct object of the event
//----------------------------------------------------------------------------------------
TDescriptor TDescriptor::GetDirectObject()
{
return GetDescriptor(keyDirectObject);
} // TDescriptor::GetDirectObject
//----------------------------------------------------------------------------------------
// TDescriptor::GetErrorCode:
//
// Get an error code
//----------------------------------------------------------------------------------------
long TDescriptor::GetErrorCode()
{
return GetLongParameter(keyErrorNumber);
} // TDescriptor::GetErrorCode
//----------------------------------------------------------------------------------------
// TDescriptor::PutDescriptor:
//
// Put a TDescriptor into the event
//----------------------------------------------------------------------------------------
void TDescriptor::PutDescriptor(AEKeyword key, TDescriptor data)
{
FailErr(AEPutParamDesc(*this, key, data));
} // TDescriptor::PutDescriptor
//----------------------------------------------------------------------------------------
// TDescriptor::PutParameterPtr:
//
// Create a descriptor from a block of data and insert it into the record
//----------------------------------------------------------------------------------------
void TDescriptor::PutParameterPtr(AEKeyword key, DescType typeCode, Ptr dataPtr, Size dataSize)
{
FailErr(AEPutParamPtr(*this, key, typeCode, dataPtr, dataSize));
} // TDescriptor::PutParameterPtr
//----------------------------------------------------------------------------------------
// TDescriptor::PutParameterHandle:
//----------------------------------------------------------------------------------------
void TDescriptor::PutParameterHandle(AEKeyword key, DescType typeCode, Handle dataHandle)
{
short handleState;
Size dataSize;
//
// Feature: if the dataHandle is nil, nothing is added to the AERecord.
//
if(dataHandle != nil)
{
handleState = HGetState(dataHandle);
HLock(dataHandle);
dataSize = GetHandleSize(dataHandle);
this->PutParameterPtr(key,typeCode,*dataHandle,dataSize);
HSetState(dataHandle,handleState);
}
} // TDescriptor::PutParameterHandle
//----------------------------------------------------------------------------------------
// TDescriptor::PutLongParameter:
//
// Put a long parameter (type specified)
//----------------------------------------------------------------------------------------
void TDescriptor::PutLongParameter(AEKeyword key, DescType typeCode, long data)
{
this->PutParameterPtr(key, typeCode, (Ptr) &data, sizeof(long));
} // TDescriptor::PutLongParameter
//----------------------------------------------------------------------------------------
// TDescriptor::PutLongParameter:
//
// Put a long parameter (type is 'typeLongInteger', the most common case)
//----------------------------------------------------------------------------------------
void TDescriptor::PutLongParameter(AEKeyword key, long data)
{
this->PutLongParameter(key,typeLongInteger,data);
} // TDescriptor::PutLongParameter
//----------------------------------------------------------------------------------------
// TDescriptor::PutShortParameter:
//
// Put a short parameter (type specified)
//----------------------------------------------------------------------------------------
void TDescriptor::PutShortParameter(AEKeyword key, DescType typeCode, short data)
{
this->PutParameterPtr(key, typeCode, (Ptr) &data, sizeof(short));
} // TDescriptor::PutShortParameter
//----------------------------------------------------------------------------------------
// TDescriptor::PutShortParameter:
//
// Put a short parameter (type is 'typeShortInteger', the most common case)
//----------------------------------------------------------------------------------------
void TDescriptor::PutShortParameter(AEKeyword key, short data)
{
this->PutShortParameter(key,typeShortInteger,data);
} // TDescriptor::PutShortParameter
//----------------------------------------------------------------------------------------
// TDescriptor::PutResult:
//
// Put the provided descriptor into the result parameter of this event. If the data
// is a null descriptor, then put in an empty list instead.
//----------------------------------------------------------------------------------------
void TDescriptor::PutResult(TDescriptor data)
{
OSErr err = noErr;
//
// If there's nothing in the data, then insert an empty list.
//
if(data.IsNullDescriptor())
{
TDescriptor emptyList;
Try
{
emptyList.MakeEmptyList();
this->PutDescriptor(keyAEResult, emptyList);
emptyList.Dispose();
}
Catch(err)
{
emptyList.Dispose();
Throw(err);
}
}
else
{
this->PutDescriptor(keyAEResult,data);
}
} // TDescriptor::PutResult
//----------------------------------------------------------------------------------------
// TDescriptor::PutErrorCode:
//
// Put an error code
//----------------------------------------------------------------------------------------
void TDescriptor::PutErrorCode(long theErr)
{
this->PutLongParameter(keyErrorNumber,theErr);
} // TDescriptor::PutErrorCode
//----------------------------------------------------------------------------------------
// TDescriptor::Resolve:
//----------------------------------------------------------------------------------------
TTokenDescriptor TDescriptor::Resolve()
{
return TDescriptor::Resolve(fCallbackFlags);
} // TDescriptor::Resolve
//----------------------------------------------------------------------------------------
// TDescriptor::Resolve:
//
// Resolves a list of object specifiers into a list of tokens. A null descriptor will
// resolve to a token to the null container.
//
// n.b. AEResolve will return an error if you pass it a null descriptor; this is why
// we include 'magic' checking for null descriptors here.
//----------------------------------------------------------------------------------------
TTokenDescriptor TDescriptor::Resolve(short callbackFlags)
{
TTokenDescriptor resolvedToken;
TTokenDescriptor intermediate;
TDescriptor descriptor;
//
// First: special checking for null descriptors
//
if(this->IsNullDescriptor())
{
resolvedToken = CreateNullContainerToken();
}
//
// Next, process non-lists
//
else if(this->DescriptorType() != typeAEList)
{
//
// If a pre-resolve proc was installed, then call it.
//
// The Scriptable Finder uses this for resolving token
// types that AEResolve does not recognize (e.g. alias
// records)
//
if(gPreResolveProc != nil)
{
resolvedToken = (*gPreResolveProc)(*this);
}
//
// If the pre-resolve proc did not resolve the token,
// then call AEResolve
//
if(resolvedToken.IsNullDescriptor())
FailErr(AEResolve(*this, callbackFlags, resolvedToken));
}
//
// If we have a list, try to resolve each element of the list in turn
//
else
{
OSErr err = noErr;
Try
{
FOREACHDESCRIPTOR(this, descriptor)
{
//
// We do not want to dispose of the intermediate token descriptor
// because its data is adopted by the 'result' token descriptor.
//
intermediate = descriptor.Resolve(callbackFlags);
resolvedToken.AdoptToken(intermediate);
intermediate.MakeNull();
}
}
Catch(err)
{
descriptor.Dispose();
intermediate.DisposeToken();
resolvedToken.DisposeToken();
Throw(err);
}
}
return resolvedToken;
} // TDescriptor::Resolve
//========================================================================================
// CLASS TAEvent
//
// AppleEvents are just like AERecords, but they can contain attributes as well as
// parameters.
//========================================================================================
//----------------------------------------------------------------------------------------
// TAEvent::TAEvent:
//----------------------------------------------------------------------------------------
TAEvent::TAEvent()
{
} // TAEvent::TAEvent
//----------------------------------------------------------------------------------------
// TAEvent::MakeAppleEvent:
//----------------------------------------------------------------------------------------
void TAEvent::MakeAppleEvent(AEEventClass eventClass, AEEventID eventID,
const TDescriptor& target, short returnID, long transactionID)
{
FailErr(AECreateAppleEvent(eventClass, eventID,
(const AEAddressDesc *) &target, returnID, transactionID, *this));
} // TAEvent::MakeAppleEvent
//----------------------------------------------------------------------------------------
// TAEvent::MakeAppleEvent:
//----------------------------------------------------------------------------------------
void TAEvent::MakeAppleEvent(AEEventClass eventClass, AEEventID eventID,
const ProcessSerialNumber& psn, short returnID, long transactionID)
{
TDescriptor address;
address.CopyData(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber));
this->MakeAppleEvent(eventClass, eventID, address, returnID, transactionID);
address.Dispose();
} // TAEvent::MakeAppleEvent
#define kCheckAEM 0
#define kDontUseSelfSend 1
#define kSelfSendSafe 2
short gCanUseSelfSend = kCheckAEM;
//----------------------------------------------------------------------------------------
// TAEvent::MakeEventAddressedToSelf:
//----------------------------------------------------------------------------------------
void TAEvent::MakeEventAddressedToSelf(AEEventClass eventClass, AEEventID eventID, short returnID, long transactionID)
{
ProcessSerialNumber current; // create psn for the current process
current.highLongOfPSN = 0;
current.lowLongOfPSN = kCurrentProcess;
//
// Old versions of the AEM leak memory if send-to-self is used
//
if(gCanUseSelfSend == kCheckAEM)
{
long aevtSelector = 0;
OSErr err = Gestalt('evnt', &aevtSelector);
gCanUseSelfSend = ((aevtSelector & 2) != 0) ? kSelfSendSafe : kDontUseSelfSend;
}
//
// Don't make the self-addressed event unless it is safe to do so
//
if(gCanUseSelfSend == kSelfSendSafe)
{
this->MakeAppleEvent(eventClass, eventID, current, returnID, transactionID);
}
else
FailErr(errAEEventNotHandled);
} // TAEvent::MakeEventAddressedToSelf
//----------------------------------------------------------------------------------------
// TAEvent::MakeEventAddressedToSystem:
//----------------------------------------------------------------------------------------
void TAEvent::MakeEventAddressedToSystem(AEEventClass eventClass, AEEventID eventID, short returnID, long transactionID)
{
ProcessSerialNumber systemPSN; // create psn for the System
systemPSN.highLongOfPSN = 0;
systemPSN.lowLongOfPSN = kSystemProcess;
this->MakeAppleEvent(eventClass, eventID, systemPSN, returnID, transactionID);
} // TAEvent::MakeEventAddressedToSystem
//----------------------------------------------------------------------------------------
// TAEvent::Send:
//----------------------------------------------------------------------------------------
void TAEvent::Send( TAEvent* reply,
AESendMode sendMode,
AESendPriority sendPriority,
long timeOutInTicks,
AEIdleUPP idleProc,
AEFilterUPP filterProc)
{
FailErr(AESend(*this, *reply, sendMode, sendPriority, timeOutInTicks, idleProc, filterProc));
} // TAEvent::Send
#define kAEDontExecute 0x2000 // for SendMode, when you just want an event recorded, not executed
//----------------------------------------------------------------------------------------
// TAEvent::SendNoExecute:
//
// This routine sends the event with the 'kAEDontExecute' bit set, so that the
// event will be recorded, but the recipient will not execute it. The event is
// also sent 'no reply', since it does not make sense to expect a result from
// a command that is not actually executed.
//----------------------------------------------------------------------------------------
void TAEvent::SendNoExecute()
{
//
// The reply isn't actuall filled in due to the kAENoReply flag
//
TAEvent reply;
Send(&reply, kAENoReply+kAEDontExecute);
} // TAEvent::SendNoExecute
//----------------------------------------------------------------------------------------
// TAEvent::SuspendTheCurrentEvent:
//----------------------------------------------------------------------------------------
void TAEvent::SuspendTheCurrentEvent()
{
FailErr(AESuspendTheCurrentEvent(*this));
} // TAEvent::SuspendTheCurrentEvent
//----------------------------------------------------------------------------------------
// TAEvent::ResumeTheCurrentEvent:
//----------------------------------------------------------------------------------------
void TAEvent::ResumeTheCurrentEvent(TAEvent* reply, AEEventHandlerUPP dispatcher, long refCon)
{
FailErr(AEResumeTheCurrentEvent(*this, *reply, dispatcher, refCon));
} // TAEvent::ResumeTheCurrentEvent
//----------------------------------------------------------------------------------------
// TAEvent::SetTheCurrentEvent:
//----------------------------------------------------------------------------------------
void TAEvent::SetTheCurrentEvent()
{
FailErr(AESetTheCurrentEvent(*this));
} // TAEvent::SetTheCurrentEvent
//----------------------------------------------------------------------------------------
// TAEvent::ResetTimer:
//
// Note: requires that this event be a 'reply' event passed to one of our event
// handlers by the AppleEvent manager
//----------------------------------------------------------------------------------------
void TAEvent::ResetTimer()
{
FailErr(AEResetTimer(*this));
} // TAEvent::ResetTimer
//----------------------------------------------------------------------------------------
// TAEvent::SpecifyThatParameterIsOptional:
//----------------------------------------------------------------------------------------
void TAEvent::SpecifyThatParameterIsOptional(AEKeyword theOptionalKeyword)
{
TDescriptor optionalKeywordsList;
TDescriptor optionalKeyword;
OSErr err = noErr;
Try
{
//
// ◊Script: We need to test to see if keyOptionalKeywordAttr
// already exists, and if so, then just add one more element to
// the list that is already inside the event.
//
optionalKeywordsList.MakeList();
optionalKeyword.MakeKeyword(theOptionalKeyword);
optionalKeywordsList.AddDescriptor(optionalKeyword);
optionalKeyword.Dispose();
this->PutAttribute(keyOptionalKeywordAttr, optionalKeywordsList);
optionalKeywordsList.Dispose();
}
Catch(err)
{
optionalKeyword.Dispose();
optionalKeywordsList.Dispose();
Throw(err);
}
} // TAEvent::SpecifyThatParameterIsOptional
//----------------------------------------------------------------------------------------
// TAEvent::GetAttribute:
//----------------------------------------------------------------------------------------
TDescriptor TAEvent::GetAttribute(AEKeyword key, DescType desiredType /* = typeWildCard */)
{
TDescriptor result;
FailErr(AEGetAttributeDesc(*this, key, desiredType, result));
return result;
} // TAEvent::GetAttribute
//----------------------------------------------------------------------------------------
// TAEvent::GetLongAttribute:
//----------------------------------------------------------------------------------------
long TAEvent::GetLongAttribute(AEKeyword key)
{
DescType typeCode;
long actualSize;
long result;
FailErr(AEGetAttributePtr(*this, key, typeLongInteger, &typeCode, (Ptr)&result, sizeof(long), &actualSize));
return result;
} // TAEvent::GetLongAttribute
//----------------------------------------------------------------------------------------
// TAEvent::PutAttribute:
//----------------------------------------------------------------------------------------
void TAEvent::PutAttribute(AEKeyword key, TDescriptor attribute)
{
FailErr(AEPutAttributeDesc(*this, key, attribute));
} // TAEvent::PutAttribute
//----------------------------------------------------------------------------------------
// PutOptionalDescriptor:
//----------------------------------------------------------------------------------------
void TAEvent::PutOptionalDescriptor(AEKeyword key, TDescriptor data)
{
this->PutDescriptor(key, data);
this->SpecifyThatParameterIsOptional(key);
} // TAEvent::PutOptionalDescriptor
//----------------------------------------------------------------------------------------
// TAEvent::PutLongAttribute:
//----------------------------------------------------------------------------------------
void TAEvent::PutLongAttribute(AEKeyword key, long attributeValue)
{
FailErr(AEPutAttributePtr(*this, key, typeLongInteger, (Ptr)&attributeValue, sizeof(long)));
} // TAEvent::PutLongAttribute
//========================================================================================
// CLASS TTokenDescriptor
//
// The class TTokenDescriptor represents descriptors returned by AEResolve
//========================================================================================
//----------------------------------------------------------------------------------------
// TTokenDescriptor::TTokenDescriptor:
//----------------------------------------------------------------------------------------
TTokenDescriptor::TTokenDescriptor()
{
fDescriptorType = typeNull;
fDataHandle = nil;
} // TTokenDescriptor::TTokenDescriptor
//----------------------------------------------------------------------------------------
// TTokenDescriptor::TTokenDescriptor:
//----------------------------------------------------------------------------------------
TTokenDescriptor::TTokenDescriptor(TDescriptor desc)
{
this->fDescriptorType = desc.DescriptorType();
this->fDataHandle = desc.DataHandle();
} // TTokenDescriptor::TTokenDescriptor
//----------------------------------------------------------------------------------------
// TTokenDescriptor::DisposeToken:
//
// It is very important that token descriptors be disposed of by AEDisposeToken,
// _not_ AEDisposeDesc.
//----------------------------------------------------------------------------------------
void TTokenDescriptor::DisposeToken()
{
AEDisposeToken(*this); // Should fail on error? Probably not.
// FailErr(AEDisposeDesc(*this));
} // TTokenDescriptor::DisposeToken
//----------------------------------------------------------------------------------------
// TTokenDescriptor::TokenHandle:
//
// Return the TTokenObject stored inside the token descriptor
//----------------------------------------------------------------------------------------
TAbstractScriptableObject* TTokenDescriptor::TokenHandle()
{
Handle tokenHandle = this->DataHandle();
TAbstractScriptableObject* tokenObject = nil;
if((this->DescriptorType() != typeTokenObject) || (tokenHandle == nil))
{
//
// ••• What error code should we fail with here?
//
FailErr(errAENoSuchObject);
}
//
// tokenHandle is a handle that contains a TTokenObject*,
// so it is a pointer to a pointer to a TTokenObject* (wow)
//
tokenObject = ** ((TAbstractScriptableObject***) tokenHandle);
return tokenObject;
} // TTokenDescriptor::TokenHandle
//----------------------------------------------------------------------------------------
// TTokenDescriptor::AdoptToken:
//
// IMPORTANT: ADOPTS THE TOKEN PASSED TO IT
//----------------------------------------------------------------------------------------
void TTokenDescriptor::AdoptToken(TTokenDescriptor& tokenDescriptor)
{
//
// Don't adopt the new token if it is empty
//
if(tokenDescriptor.IsNullDescriptor() == false)
{
//
// If this descriptor is empty, it is easy to adopt the new token
//
if( this->IsNullDescriptor() )
{
TDescriptor::AdoptHandle(tokenDescriptor.DescriptorType(), tokenDescriptor.DataHandle() );
tokenDescriptor.MakeNull();
}
else
{
TAbstractScriptableObject* tokenObject = tokenDescriptor.TokenHandle();
this->AdoptToken(tokenObject);
//
// n.b. 'Dispose', not 'DisposeToken'. The token that
// was formerly contained in tokenDescriptor is now referenced
// in 'this' token descriptor, so it would be a bad idea to
// delete it.
//
tokenDescriptor.Dispose();
}
}
} // TTokenDescriptor::AdoptToken
//----------------------------------------------------------------------------------------
// TTokenDescriptor::AdoptToken:
//----------------------------------------------------------------------------------------
void TTokenDescriptor::AdoptToken(TAbstractScriptableObject* tokenObject)
{
//
// Don't adopt the new token if it is not a valid object
//
if(tokenObject != nil)
{
//
// If this descriptor is empty, then create a new
// token descriptor to hold a pointer to the tokenObject.
//
if(this->IsNullDescriptor() )
{
Handle newHandle = NewHandle( sizeof(Ptr) );
** ((TAbstractScriptableObject***)newHandle) = tokenObject;
TDescriptor::AdoptHandle(typeTokenObject, newHandle);
}
//
// If there is already something here, then we need
// to somehow merge the two tokens together. In the
// Scriptable Finder, we want to create a mark token
// to do the merge. However, MoreAEM does not depend
// on files such as MarkToken.h which are outside of
// the Blue folder. Therefore, we call a callback proc
// to fill in the mark token. The callback proc is
// installed in InitializeScriptability.
//
else
{
if(gMergeTokensProc == nil)
FailErr(errAEEventNotHandled);
//
// The MergeTokensProc takes two TAbstractScriptableObject*'s
// and merges them into another TAbstractScriptableObject*
// (which adopts the two original tokens).
//
TAbstractScriptableObject* mergedTokens = (*gMergeTokensProc)(this->TokenHandle(), tokenObject);
Handle tokenHandle = this->DataHandle();
** ((TAbstractScriptableObject***) tokenHandle) = mergedTokens;
}
}
} // TTokenDescriptor::AdoptToken
#pragma segment CFrontCruft